<template>
  <div class="chat-container">

    <!-- WebSocket 状态提示 -->
    <div class="socket-status" :class="socketStatus">
      <span v-if="socketStatus === 'connecting'">🟠 连接中...</span>
      <span v-else-if="socketStatus === 'open'">🟢 已连接</span>
      <span v-else-if="socketStatus === 'closed'">
        🔴 已断开
        <button @click="manualReconnect" class="reconnect-btn">重连</button>
      </span>
      <span v-else-if="socketStatus === 'error'">
        ⚠️ 连接出错
        <button @click="manualReconnect" class="reconnect-btn">重连</button>
      </span>
    </div>


    <!-- 聊天消息区 -->
    <div class="msg-list" ref="chatList">
      <div v-for="msg in chatMessages" :key="msg.id" :class="['msg', msg.role === 'user' ? 'msg-user' : 'msg-ai']">
        <!-- <div class="avatar" v-if="msg.role === 'ai'">💡</div> -->
        <div class="avatar" v-if="msg.role === 'ai'">
          <img src="@/assets/images/avatar/openai.svg" alt="AI Avatar" class="avatar-img" />
        </div>
        <div class="msg-content" v-html="msg.renderedContent"></div>
        <div class="avatar" v-if="msg.role === 'user'">🧑</div>
      </div>

      <!-- AI 打字中... -->
      <div class="ai-loading" v-if="loading">
        <span style="margin-right: 10px;">AI 正在输入</span>
        <div class="dot-flash">
          <div class="dot" v-for="i in 3" :key="i" :style="{ animationDelay: i * 0.2 + 's' }"></div>
        </div>
      </div>
    </div>


    <!-- 底部输入栏 -->

    <div class="input-bar1" :class="{ 'input-bottom': chatMessages.length > 0 }">
      <!-- 附件列表展示，放在输入框上方 -->
      <div v-if="selectedFiles.length > 0" class="file-list">
        <div class="file-item" v-for="(file, index) in selectedFiles" :key="file.name + index">
          <span>{{ file.name }}</span>
          <button class="remove-file" @click="removeFile(index)">❌</button>
        </div>
      </div>
      <div class="input-bar">

        <!-- 附件按钮 -->
        <input ref="fileInput" type="file" accept=".txt,.pdf,.doc,.mp4,.docx,image/*" multiple style="display:none"
          @change="handleFileSelect" />
        <button class="attach-btn" @click="$refs.fileInput.click()">📎</button>

        <div class="input-wrapper">
          <textarea ref="inputBox" v-model="userInput" @keyup.enter="handleSend" @paste="handlePaste"
            placeholder="请输入问题..." class="input-box" rows="1"></textarea>
        </div>

        <!-- 新增：模型选择 -->
        <el-select v-model="selectedModel" placeholder="模型选择" style="margin-top: 10px;">
          <el-option v-for="item in selectedModelOptions" :key="item.value" :label="item.label" :value="item.value">
          </el-option>
        </el-select>
        <!-- 新增：知识库选择 -->
        <el-select v-model="selectedKB" placeholder="知识库选择" style="margin-top: 10px;">
          <el-option v-for="item in selectedKBOptions" :key="item.value" :label="item.label" :value="item.value">
          </el-option>
        </el-select>
      </div>
    </div>
  </div>
</template>

<script>
import { marked } from 'marked'
import { uploadFile } from '@/api/file'
import { nextTick } from 'vue'
import hljs from 'highlight.js'
import { getFileListByPath } from '@/api/knowledge.js'
import 'highlight.js/styles/github.css' // 你可以换成其他主题样式

marked.setOptions({
  breaks: true,
  gfm: true,
  highlight(code, lang) {
    return lang && hljs.getLanguage(lang)
      ? hljs.highlight(code, { language: lang }).value
      : hljs.highlightAuto(code).value;
  }
})

export default {
  data() {
    return {
      selectedModel: 'gpt-4.1',//所选模型
      selectedModelOptions: [
        {
          label: '🚀 GPT-4.1（推荐文本模型）',
          value: 'gpt-4.1'
        },
        {
          label: '🌌 GPT-4.1-2025-04-14（最新版）',
          value: 'gpt-4.1-2025-04-14'
        },
        {
          label: '🔮 GPT-4o（多模态旗舰）',
          value: 'gpt-4o'
        },
        {
          label: '🧠 O3（推理优化版）',
          value: 'o3'
        },
        {
          label: '📘 GPT-4（旧版）',
          value: 'gpt-4'
        },
        {
          label: '💸 GPT-3.5 Turbo（低成本）',
          value: 'gpt-3.5-turbo'
        }
      ],
      selectedKB: '',
      selectedKBOptions: [
        {
          label: '📚 未使用知识库',
          value: '📚 未使用知识库'
        }, {
          label: '📘 产品文档库',
          value: '📘 产品文档库'
        }, {
          label: '📒 FAQ 知识库',
          value: '📒 FAQ 知识库'
        }, {
          label: '📙 内部资料库',
          value: '📙 内部资料库'
        }
      ],//所选知识库
      socketStatus: 'connecting', // 初始状态
      socket: null,
      reconnectAttempts: 0,         // 当前重试次数
      maxReconnectAttempts: 20,      // 最大重试次数
      reconnectDelay: 2000,         // 初始重连延迟(ms)
      reconnectTimer: null,
      selectedFiles: [],  // 改成数组支持多文件

      selectedFile: null, // 新增：已选文件
      chatMessages: [
        {
          id: Date.now(),
          role: 'ai',
          content: '嘿！我是 **AI 小助手**，有任何问题都可以问我哦～',
          renderedContent: '',
        },
      ],
      userInput: '',
      loading: false,
      currentAiMessageId: null,
      typingQueue: [],
      typingTimer: null,
      isTyping: false,
    }
  },
  mounted() {
    this.getFileListByPath()
    // 初始化 Markdown 渲染
    this.chatMessages.forEach((msg) => {
      msg.renderedContent = marked.parse(msg.content)
    })
    this.initSocket()

    this.adjustInputHeight() // 初始化一次
  },
  watch: {
    userInput() {
      this.adjustInputHeight()
    }
  },
  beforeDestroy() {
    if (this.typingTimer) {
      clearTimeout(this.typingTimer)
    }
    if (this.reconnectTimer) {
      clearTimeout(this.reconnectTimer)
    }
    if (this.socket) {
      this.socket.close()
    }
  },
  methods: {

    /**
     * 查询知识库列表
     */
    getFileListByPath() {
      getFileListByPath().then(res => {
        if (res && res.data && res.data.data && res.data.data.records) {
          this.selectedKBOptions = res.data.data.records.map(item => ({
            label: item.name,
            value: item.knowledgeCode
          }))
        }
      })
    },
    adjustInputHeight() {
      nextTick(() => {
        const el = this.$refs.inputBox
        if (!el) return
        el.style.height = 'auto' // 重置高度
        const lineHeight = parseInt(getComputedStyle(el).lineHeight) || 24
        const maxLines = 3
        const maxHeight = lineHeight * maxLines + 20 // 20px padding 预留
        el.style.height = Math.min(el.scrollHeight, maxHeight) + 'px'
      })
    },
    /**
     * 复制粘贴文件上传
     */
    handlePaste(e) {
      const clipboardData = e.clipboardData
      if (!clipboardData) return

      const files = []
      for (let item of clipboardData.items) {
        if (item.kind === 'file') {
          const file = item.getAsFile()
          if (file) files.push(file)
        }
      }

      if (files.length > 0) {
        // 追加文件，避免覆盖
        this.selectedFiles.push(...files)
        console.log("粘贴添加文件：")
        console.log(this.selectedFiles)
        e.preventDefault() // 阻止粘贴到输入框
      }
    },
    /**
     * 手动重连
     */
    manualReconnect() {
      console.log('[WebSocket] 用户手动触发重连')
      // 清理已有自动重连定时器，避免冲突
      if (this.reconnectTimer) {
        clearTimeout(this.reconnectTimer)
        this.reconnectTimer = null
      }
      this.reconnectAttempts = 0 // 重置重试计数
      this.initSocket()          // 直接重新连接

    },
    // 处理文件选择（支持多选）
    handleFileSelect(e) {
      const files = Array.from(e.target.files)
      if (!files.length) return
      // 追加文件，避免覆盖
      this.selectedFiles.push(...files)
      console.log("已选择文件：")
      console.log(this.selectedFiles)
      // 清空 input 以便同名文件也能被选中
      e.target.value = null
    },
    // 删除附件
    removeFile(index) {
      this.selectedFiles.splice(index, 1)
    },
    /**
     * 消息Id 生成
     */
    generateId() {
      return Date.now() + Math.random()
    },
    /**
     * 初始化 Web Socket 服务
     */
    initSocket() {

      if (this.socket) {
        this.socket.close()
        this.socket = null
      }

      this.socket = new WebSocket('ws://127.0.0.1:9876/chat-ws')

      this.socketStatus = 'connecting'

      this.socket.addEventListener('open', () => {
        console.log('WebSocket 已连接')
        this.socketStatus = 'open'
        this.reconnectAttempts = 0  // 成功连接后重置计数
        if (this.reconnectTimer) {
          clearTimeout(this.reconnectTimer)
          this.reconnectTimer = null
        }
      })

      this.socket.addEventListener('message', (event) => {
        if (event.data === '[DONE]') {
          this.loading = false
          this.currentAiMessageId = null
          return
        }
        this.queueTextForTyping(event.data)
      })

      this.socket.addEventListener('close', () => {
        console.log('WebSocket 已关闭')
        this.socketStatus = 'closed'
        this.tryReconnect()
      })

      this.socket.addEventListener('error', (error) => {
        console.error('WebSocket 错误:', error)
        this.socketStatus = 'error'
        this.tryReconnect()
      })
    },
    /** WebSocket 重连 逻辑 */
    tryReconnect() {
      if (this.reconnectAttempts >= this.maxReconnectAttempts) {
        console.warn('[WebSocket] 已达到最大重连次数，不再重试')
        return
      }

      if (this.reconnectTimer) return // 已有重连计划，避免重复

      const delay = this.reconnectDelay * (this.reconnectAttempts + 1) // 简单指数退避
      console.log(`[WebSocket] ${delay}ms 后尝试第 ${this.reconnectAttempts + 1} 次重连`)

      this.reconnectTimer = setTimeout(() => {
        console.log('[WebSocket] 开始重连...')
        this.reconnectAttempts++
        this.initSocket()
      }, delay)
    },
    // 处理消息发送
    async handleSend() {
      const msg = this.userInput.trim()

      // ✅ 校验输入和 WebSocket 状态
      if (!msg && this.selectedFiles.length === 0) return
      if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {
        console.warn('[Chat] 🚫 WebSocket 未连接，消息发送失败')
        return
      }

      let contentWithFiles = msg
      if (this.selectedFiles.length) {
        const names = this.selectedFiles.map(f => f.name).join(', ')
        contentWithFiles += `\n\n📎 附件: ${names}`
      }

      this.chatMessages.push({
        id: this.generateId(),
        role: 'user',
        content: contentWithFiles,
        renderedContent: marked.parse(contentWithFiles), // ✅ 附件名也会支持 Markdown 渲染
      })

      // 清空输入框，开启加载
      this.userInput = ''
      this.loading = true
      this.scrollToBottom()

      // 2. 组装上下文（方便后端保持会话）
      const context = this.chatMessages
        .map((m) => (m.role === 'user' ? '用户：' : 'AI：') + m.content)
        .join('\n')

      try {
        // 3. 判断是发送附件还是纯文本
        if (this.selectedFiles.length) {

          console.log('[Chat] 📎 正在上传附件:')

          const fileUrlList = []

          for (let i = 0; i < this.selectedFiles.length; i++) {

            const resp = await this.uploadFile(this.selectedFiles[i])

            console.log('[Chat] 📎 上传附件成功:', resp)

            for (let j = 0; j < resp.length; j++) {
              fileUrlList.push(resp[j])
            }

          }

          this.safeSend({
            type: 'file',
            name: '附件',
            modelName: this.selectedModel,
            data: fileUrlList,
            knowledgeCode: this.selectedKB,
            text: msg || '',
            context
          })

          this.selectedFiles = []
        } else {
          console.log('[Chat] 💬 发送文本:', msg)
          this.safeSend({
            type: 'text',
            modelName: this.selectedModel,
            knowledgeCode: this.selectedKB,
            text: msg,
            context
          })
        }
      } catch (err) {
        console.error('[Chat] ❌ 消息发送失败:', err)
      }
    },

    /**
     * ✅ 封装安全的 WebSocket 发送方法，避免 TEXT_PARTIAL_WRITING 错误
     */
    safeSend(data) {
      if (this.socket && this.socket.readyState === WebSocket.OPEN) {
        this.socket.send(typeof data === 'string' ? data : JSON.stringify(data))
      } else {
        console.warn('[Chat] 🚫 WebSocket 未连接，消息未发送')
      }
    },
    // 文件处理为Base64
    fileToBase64(file) {
      return new Promise((resolve, reject) => {
        const reader = new FileReader()
        reader.readAsDataURL(file)
        reader.onload = () => resolve(reader.result)
        reader.onerror = reject
      })
    },
    queueTextForTyping(text) {
      const chars = Array.from(text)
      this.typingQueue.push(...chars)
      if (!this.isTyping) {
        this.startTyping()
      }
    },
    startTyping() {
      this.isTyping = true

      let last = this.chatMessages.find((msg) => msg.id === this.currentAiMessageId)
      if (!last) {
        last = { id: this.generateId(), role: 'ai', content: '', renderedContent: '' }
        this.chatMessages.push(last)
        this.currentAiMessageId = last.id
      }

      const typeNext = () => {
        if (this.typingQueue.length === 0) {
          this.isTyping = false
          return
        }

        const nextChar = this.typingQueue.shift()
        last.content += nextChar
        last.renderedContent = marked.parse(last.content)
        this.$forceUpdate()
        this.scrollToBottom()

        this.$nextTick(() => {
          hljs.highlightAll() // 语法高亮重新执行
        })

        this.typingTimer = setTimeout(typeNext, 20)
      }

      typeNext()
    },
    scrollToBottom() {
      this.$nextTick(() => {
        const el = this.$refs.chatList
        if (el) el.scrollTop = el.scrollHeight
      })
    },
    /**
     * 文件上传
     */
    async uploadFile(file) {
      const formData = new FormData()

      formData.append('file', file)  // 假设后端字段是 files，多个同名字段

      const res = await uploadFile(formData);

      return res.data.data || []
    }
  }
}
</script>

<!-- <style scoped>
.selector {
  padding: 6px 10px;
  border-radius: 8px;
  border: 1px solid #ddd;
  background: #fafafa;
  font-size: 13px;
  cursor: pointer;
  transition: all 0.2s;
}

.selector:hover {
  border-color: #aaa;
  background: #f5f5f5;
}

.attach-btn {
  background: none;
  border: none;
  font-size: 20px;
  cursor: pointer;
}

.file-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  max-height: 100px;
  min-height: 100px;
  margin-bottom: 20px;
  overflow-y: auto;
  padding: 6px 12px;
  height: 50px;
  border-radius: 8px;
  margin-bottom: 20px;
}

.file-item {
  background: #fff;
  padding: 4px 8px;
  border-radius: 12px;
  box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
  display: flex;
  align-items: center;
  font-size: 13px;
  color: #333;
  height: 32px;
}

.file-item .remove-file {
  background: transparent;
  border: none;
  margin-left: 6px;
  cursor: pointer;
  font-size: 14px;
  color: #999;
  transition: color 0.2s;
}

.file-item .remove-file:hover {
  color: #f5222d;
}

.reconnect-btn {
  margin-left: 12px;
  padding: 2px 8px;
  font-size: 12px;
  cursor: pointer;
  border: 1px solid #1890ff;
  background: #fff;
  color: #1890ff;
  border-radius: 4px;
  transition: all 0.2s ease;
}

.reconnect-btn:hover {
  background: #1890ff;
  color: #fff;
}

/** WebSocket 连接状态*/
.socket-status {
  padding: 6px 12px;
  font-size: 13px;
  text-align: center;
  user-select: none;
}

.socket-status.connecting {
  color: #fa8c16;
  /* 橙色 */
}

.socket-status.open {
  color: #52c41a;
  /* 绿色 */
}

.socket-status.closed {
  color: #f5222d;
  /* 红色 */
}

.socket-status.error {
  color: #fa541c;
  /* 深橙红 */
}

/* 添加附件 */
.attach-btn {
  background: transparent;
  border: none;
  font-size: 20px;
  cursor: pointer;
  padding: 0 8px;
  margin: 0 0 8px 0;
  /* 关键修改：底部间距 */
}

.file-preview {
  display: flex;
  align-items: center;
  font-size: 14px;
  background: #f4f6f8;
  padding: 6px 10px;
  border-radius: 6px;
  margin: 6px 0 0 0;
}

.file-preview .remove-file {
  background: transparent;
  border: none;
  margin-left: 8px;
  cursor: pointer;
  font-size: 14px;
}

/* ======================== */
pre code::before {
  content: attr(class);
  position: absolute;
  top: 0;
  right: 0;
  font-size: 12px;
  color: #999;
  background: #eee;
  padding: 2px 8px;
  border-radius: 0 0 0 10px;
}

/* 代码块样式，淡紫色背景+圆角+阴影+边框 */
.msg-content pre {
  background: #f6f7fb;
  /* 淡紫灰色背景 */
  border-radius: 12px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
  border: 1px solid #ececec;
  margin: 18px 0;
  position: relative;
  overflow: auto;
  padding: 0;
}

.msg-content pre code {
  background: transparent;
  padding: 18px;
  font-size: 15px;
  color: #2d2d2d;
  /* 稍深字体，和正文区分 */
  font-family: 'Fira Mono', 'Consolas', 'Menlo', monospace;
  display: block;
  white-space: pre-wrap;
  /* 保证换行和缩进 */
  line-height: 1.7;
}

/* 代码块左上角标签样式 */
.msg-content pre code::before {
  content: attr(class);
  position: absolute;
  top: 8px;
  right: 16px;
  font-size: 12px;
  color: #aaa;
  background: #f0f0f0;
  padding: 2px 8px;
  border-radius: 6px;
  z-index: 2;
}
</style>

<style scoped>
.avatar-img {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  object-fit: cover;
  box-shadow: none;
  background: #fff;
}

.chat-container {
  display: flex;
  flex-direction: column;
  height: 100%;
  background: #f4f6f8;
  font-family: 'Helvetica Neue', Arial, sans-serif;
  padding-bottom: 100px;
  box-sizing: border-box;
  overflow: hidden;
}

.msg-list {
  flex: 1;
  padding: 20px 12px 0;
  overflow-y: auto;
  box-sizing: border-box;
  scroll-behavior: smooth;
}

.msg {
  display: flex;
  align-items: flex-end;
  margin-bottom: 18px;
  max-width: 70%;
  font-size: 14.5px;
  line-height: 1.6;
  position: relative;
}

.msg-user {
  margin-left: auto;
  justify-content: flex-end;
}

.msg-user .msg-content {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: #fff;
  border-radius: 18px 4px 18px 18px;
  padding: 10px 14px;
  box-shadow: 0 2px 10px rgba(102, 126, 234, 0.25);
  min-width: 100px;
  max-width: 800px;
}

.msg-user .avatar {
  margin-left: 8px;
  border: 2px solid #667eea;
}

.msg-ai {
  margin-right: auto;
  justify-content: flex-start;
}

.msg-ai .msg-content {
  background: #fff;
  color: #333;
  border-radius: 4px 18px 18px 18px;
  padding: 10px 14px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
  min-width: 100px;
  max-width: 800px;
}

.msg-ai .avatar {
  margin-right: 8px;
  border: 2px solid #f1f2f6;
}

.avatar {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  flex-shrink: 0;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.12);
}

.input-bar1 {
  position: fixed;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
  max-width: 720px;
  gap: 12px;
  padding: 12px 16px;
  border-radius: 20px;
}

.input-bar {
  margin-top: 20px;
  position: fixed;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
  max-width: 720px;
  display: flex;
  gap: 12px;
  padding: 12px 16px;
  background-color: white;
  box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.08);
  border-radius: 20px;
}

.input-wrapper {
  display: flex;
  width: 100%;
}

.input-box {
  flex: 1;
  height: auto;
  /* 高度自适应 */
  min-height: 20px;
  /* 一行高度 */
  max-height: 120px;
  /* 三行高度 */
  resize: none;
  /* 禁止手动拉伸 */
  border: none;
  background: #f4f6f8;
  border-radius: 20px;
  padding: 10px 14px;
  font-size: 15px;
  line-height: 1.4;
  outline: none;
  overflow-y: auto;

  font-family: monospace;
  /* 等宽字体，更好显示缩进 */
  white-space: pre-wrap;
  /* 保留空格、制表符和换行，同时自动换行 */
  word-break: break-word;
  /* 防止长行撑破容器 */
}



.ai-loading {
  display: flex;
  align-items: center;
  color: #888;
  font-size: 14px;
  margin-left: 12px;
}

.dot-flash {
  display: flex;
  margin-left: 10px;
}

.dot {
  width: 8px;
  height: 8px;
  background-color: #1890ff;
  border-radius: 50%;
  margin-left: 6px;
  animation: flashDot 1.2s infinite;
}

@keyframes flashDot {
  0% {
    opacity: 0.2;
    transform: scale(0.8);
  }

  50% {
    opacity: 1;
    transform: scale(1.2);
  }

  100% {
    opacity: 0.2;
    transform: scale(0.8);
  }
}

.msg-content h1,
.msg-content h2 {
  font-weight: bold;
  margin-top: 1em;
}

.msg-content ul {
  padding-left: 20px;
}

.msg-content a {
  color: #1890ff;
  text-decoration: underline;
}



@media (max-width: 768px) {
  .input-bar {
    padding: 10px 12px;
  }

  .input-box {
    font-size: 14px;
    padding: 8px 12px;
  }

  .msg {
    max-width: 85%;
    font-size: 14px;
  }
}
</style> -->
<style lang="less" scoped>
/* ================= 变量定义 (与主布局保持一致) ================= */
@primary-color: #00f2ff;   /* 赛博青 */
@accent-color: #7d2ae8;    /* 霓虹紫 */
@bg-glass: rgba(20, 25, 40, 0.7); /* 玻璃背景 */
@border-light: rgba(255, 255, 255, 0.1);
@text-main: #e2e8f0;
@text-sub: #94a3b8;

/* ================= 容器布局 ================= */
.chat-container {
  display: flex;
  flex-direction: column;
  height: 100%;
  /* 背景透明，透出父级的星空/科技背景 */
  background: transparent; 
  font-family: 'Inter', 'Helvetica Neue', Arial, sans-serif;
  position: relative;
  color: @text-main;
}

/* ================= WebSocket 状态 ================= */
.socket-status {
  padding: 8px;
  font-size: 12px;
  text-align: center;
  background: rgba(0, 0, 0, 0.2);
  backdrop-filter: blur(5px);
  border-bottom: 1px solid @border-light;
  transition: all 0.3s;

  &.connecting { color: #fa8c16; }
  &.open { color: #00f2ff; text-shadow: 0 0 5px rgba(0, 242, 255, 0.5); }
  &.closed { color: #ff4d4f; }
  &.error { color: #ff4d4f; }
}

.reconnect-btn {
  margin-left: 10px;
  background: transparent;
  border: 1px solid @primary-color;
  color: @primary-color;
  border-radius: 4px;
  padding: 2px 8px;
  cursor: pointer;
  font-size: 12px;
  &:hover {
    background: @primary-color;
    color: #000;
    box-shadow: 0 0 10px @primary-color;
  }
}

/* ================= 消息列表区域 ================= */
.msg-list {
  flex: 1;
  padding: 20px 20px 140px 20px; /* 底部留出输入框的高度 */
  overflow-y: auto;
  scroll-behavior: smooth;

  /* 自定义滚动条 */
  &::-webkit-scrollbar { width: 6px; }
  &::-webkit-scrollbar-track { background: transparent; }
  &::-webkit-scrollbar-thumb {
    background: rgba(255, 255, 255, 0.1);
    border-radius: 3px;
    &:hover { background: rgba(255, 255, 255, 0.2); }
  }
}

/* 单条消息布局 */
.msg {
  display: flex;
  align-items: flex-start; /* 改为顶部对齐 */
  margin-bottom: 24px;
  font-size: 15px;
  line-height: 1.6;
}

/* 头像样式 */
.avatar {
  width: 48px;
  height: 48px;
  flex-shrink: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.1);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  border: 1px solid @border-light;
  
  .avatar-img {
    width: 100%;
    height: 100%;
  }
}

/* ================= 消息气泡风格 ================= */
.msg-content {
  position: relative;
  padding: 12px 16px;
  border-radius: 12px;
  max-width: 85%;
  word-break: break-word;
  
  /* 链接样式 */
  ::v-deep a {
    color: @primary-color;
    text-decoration: none;
    border-bottom: 1px dashed @primary-color;
    &:hover { text-shadow: 0 0 5px @primary-color; }
  }
  
  /* 列表样式 */
  ::v-deep ul, ::v-deep ol { padding-left: 20px; margin: 8px 0; }
  ::v-deep li { margin-bottom: 4px; }
  
  /* 标题样式 */
  ::v-deep h1, ::v-deep h2, ::v-deep h3 {
    color: #fff;
    font-weight: 600;
    margin-top: 16px;
    margin-bottom: 8px;
    &:first-child { margin-top: 0; }
  }
}

/* AI 消息 (左侧) */
.msg-ai {
  .avatar { margin-right: 12px; box-shadow: 0 0 10px rgba(125, 42, 232, 0.2); }
  .msg-content {
    background: rgba(26, 31, 44, 0.8); /* 深色半透明 */
    border: 1px solid @border-light;
    border-top-left-radius: 2px;
    color: @text-main;
    box-shadow: 0 4px 15px rgba(0,0,0,0.2);
  }
}

/* ================= 核心修改点：用户消息样式 ================= */
.msg-user {
  /* 关键：靠右对齐，但保持正常的 DOM 顺序 (内容 -> 头像) */
  justify-content: flex-end; 
  flex-direction: row; 
  
  .avatar { 
    /* 头像在右边，所以间距要加在左边 */
    margin-left: 12px; 
    margin-right: 0;
    
    /* 赛博风样式 */
    border-color: @primary-color; 
    box-shadow: 0 0 8px rgba(0, 242, 255, 0.3); 
  }

  .msg-content {
    /* 气泡背景：赛博青渐变 */
    background: linear-gradient(135deg, rgba(0, 110, 255, 0.8), rgba(0, 242, 255, 0.6));
    backdrop-filter: blur(5px);
    color: #fff;
    
    /* 边框发光 */
    border: 1px solid rgba(255, 255, 255, 0.2);
    box-shadow: 0 0 15px rgba(0, 242, 255, 0.15);
    
    /* 关键：调整圆角，让尖角指向右边的头像 */
    border-radius: 12px;
    border-top-right-radius: 2px; 
  }
}

/* ================= 代码块样式深度覆盖 ================= */
::v-deep pre {
  background: #1e1e1e !important; /* 强制深色背景 */
  border-radius: 8px;
  margin: 12px 0;
  padding: 12px;
  border: 1px solid #333;
  overflow-x: auto;
  position: relative;
  
  code {
    background: transparent !important;
    color: #d4d4d4; /* 浅灰文字 */
    font-family: 'Fira Code', monospace;
    font-size: 14px;
    
    /* 滚动条 */
    &::-webkit-scrollbar { height: 6px; }
    &::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.2); border-radius: 3px; }
  }
  
  /* 语言标签 */
  &::before {
    color: @text-sub;
    background: rgba(255,255,255,0.05);
    border-radius: 0 0 0 4px;
  }
}

/* ================= 底部输入控制台 ================= */
.input-bar1 {
  /* 容器定位 */
  position: absolute; /* 改为 absolute 适应父容器 */
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
  width: 90%;
  max-width: 800px;
  z-index: 10;
  display: flex;
  flex-direction: column;
}

/* 文件预览列表 */
.file-list {
  background: rgba(20, 25, 40, 0.9);
  backdrop-filter: blur(10px);
  border: 1px solid @border-light;
  border-radius: 12px;
  padding: 8px;
  margin-bottom: 8px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  
  .file-item {
    background: rgba(0, 242, 255, 0.1);
    border: 1px solid rgba(0, 242, 255, 0.2);
    color: @primary-color;
    border-radius: 6px;
    font-size: 12px;
    padding: 4px 8px;
    display: flex;
    align-items: center;
    
    .remove-file {
      color: @text-sub;
      margin-left: 6px;
      background: none;
      border: none;
      cursor: pointer;
      &:hover { color: #ff4d4f; }
    }
  }
}

/* 主输入栏 */
.input-bar {
  position: relative;
  bottom: auto; left: auto; transform: none; /* 重置原有定位 */
  width: 100%;
  background: rgba(26, 31, 44, 0.7); /* 玻璃态 */
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid rgba(255,255,255,0.1);
  border-radius: 16px;
  padding: 12px;
  box-shadow: 0 10px 30px rgba(0,0,0,0.3);
  display: flex;
  align-items: flex-end;
  gap: 10px;
  transition: all 0.3s;

  &:focus-within {
    border-color: rgba(0, 242, 255, 0.4);
    box-shadow: 0 0 20px rgba(0, 242, 255, 0.1);
    background: rgba(26, 31, 44, 0.9);
  }
}

/* 附件按钮 */
.attach-btn {
  color: @text-sub;
  font-size: 20px;
  padding: 8px;
  border-radius: 8px;
  transition: 0.3s;
  &:hover {
    color: @primary-color;
    background: rgba(255,255,255,0.05);
    transform: scale(1.1);
  }
}

/* 输入框容器 */
.input-wrapper {
  flex: 1;
  min-height: 40px;
}

/* 文本域 */
.input-box {
  width: 100%;
  background: transparent;
  border: none;
  color: #fff;
  font-size: 15px;
  padding: 8px 0;
  line-height: 1.5;
  resize: none;
  font-family: inherit;
  
  &::placeholder { color: rgba(255,255,255,0.3); }
  &:focus { outline: none; }
  
  /* 滚动条 */
  &::-webkit-scrollbar { width: 4px; }
  &::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.1); }
}

/* Element Select 覆盖样式 (暗色适配) */
::v-deep .el-select {
  width: 140px;
  
  .el-input__inner {
    background: rgba(0,0,0,0.2);
    border: 1px solid rgba(255,255,255,0.1);
    color: @text-sub;
    height: 32px;
    line-height: 32px;
    border-radius: 6px;
    font-size: 12px;
    
    &:focus {
      border-color: @primary-color;
      color: #fff;
    }
  }
  
  .el-input__icon { line-height: 32px; }
}

/* 这里的下拉框样式可能需要写在全局或 App.vue 中，
   因为 popper-append-to-body 默认是 true。
   这里仅做 input 框的视觉优化 */

/* ================= 动画效果 ================= */
.ai-loading {
  display: flex;
  align-items: center;
  color: @primary-color;
  font-size: 13px;
  margin-top: 10px;
  margin-left: 50px; /* 对齐头像右侧 */
  
  .dot-flash {
    display: flex;
    margin-left: 6px;
    
    .dot {
      width: 6px; height: 6px;
      background: @primary-color;
      border-radius: 50%;
      margin: 0 3px;
      animation: flash 1.4s infinite ease-in-out;
      box-shadow: 0 0 5px @primary-color;
    }
  }
}

@keyframes flash {
  0%, 100% { opacity: 0.2; transform: scale(0.8); }
  50% { opacity: 1; transform: scale(1.2); }
}

/* ================= 响应式 ================= */
@media (max-width: 768px) {
  .msg-content { max-width: 90%; }
  .input-bar1 { width: 95%; bottom: 10px; }
  .input-bar { padding: 8px; }
  ::v-deep .el-select { width: 100px; }
}
</style>